﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using UtilZ.Dotnet.Ex.Log;

namespace DotnetWinFormApp
{
    internal class CusDrawControl : Control
    {
        /// <summary>
        /// 图形双缓冲缓冲区对象
        /// </summary>
        private BufferedGraphics _grafx = null;

        private readonly Timer _timer;

        /// <summary>
        /// 构造函数初始化
        /// </summary>
        public CusDrawControl()
            : base()
        {
            try
            {
                //设置绘制样式
                //ControlStyles styles = ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint |
                //    ControlStyles.Opaque | ControlStyles.OptimizedDoubleBuffer | ControlStyles.SupportsTransparentBackColor |
                //    ControlStyles.ResizeRedraw;
                //ControlStyles styles = ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint |
                //    ControlStyles.Opaque | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.SupportsTransparentBackColor;
                //this.SetStyle(styles, true);

                this.SetStyle(ControlStyles.UserPaint, true);
                this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
                this.SetStyle(ControlStyles.ResizeRedraw, true);

                this.DoubleBuffered = true;
                base.BackColor = Color.Transparent;
            }
            catch (Exception ex)
            {
                Loger.Error(ex);
            }
            //大小
            this.Size = new System.Drawing.Size(200, 200);
            //最小大小
            this.MinimumSize = this.Size;

            this._timer = new Timer();
            this._timer.Interval = 100;
            this._timer.Tick += _timer_Tick;
        }

        private void _timer_Tick(object sender, EventArgs e)
        {
            //this.Draw();
            //控制绘制形状
            this.Region = this.GetRegion();
        }


        public void StartAnimal()
        {
            this._timer.Start();
        }

        public void StopAnimal()
        {
            this._timer.Stop();
        }


        /// <summary>
        /// 重写OnSizeChanged
        /// </summary>
        /// <param name="e"></param>
        protected override void OnSizeChanged(EventArgs e)
        {
            try
            {
                //重新创建双缓冲
                this.CreateBufferedGraphics();
                this.Draw();
                base.OnSizeChanged(e);
            }
            catch (Exception ex)
            {
                Loger.Error(ex);
            }
        }

        /// <summary>
        /// 创建双缓冲绘图
        /// </summary>
        private void CreateBufferedGraphics()
        {
            // Sets the maximum size for the primary graphics buffer
            // of the buffered graphics context for the application
            // domain.  Any allocation requests for a buffer larger 
            // than this will create a temporary buffered graphics 
            // context to host the graphics buffer.
            BufferedGraphicsManager.Current.MaximumBuffer = new Size(this.Width + 1, this.Height + 1);
            BufferedGraphics grafx = null;
            //当宽度或高度为0时,缓冲区创建会报系统异常
            if (this.Width != 0 && this.Height != 0)
            {
                // Allocates a graphics buffer the size of this form
                // using the pixel format of the Graphics created by 
                // the Form.CreateGraphics() method, which returns a 
                // Graphics object that matches the pixel format of the form.
                //BufferedGraphics grafx = BufferedGraphicsManager.Current.Allocate(this.CreateGraphics(), new Rectangle(0, 0, this.Width, this.Height));
                grafx = BufferedGraphicsManager.Current.Allocate(Graphics.FromHwnd(this.Handle), new Rectangle(0, 0, this.Width, this.Height));
                grafx.Graphics.SmoothingMode = SmoothingMode.HighQuality;
                grafx.Graphics.PixelOffsetMode = PixelOffsetMode.HighSpeed;
            }

            if (this._grafx != null)
            {
                this._grafx.Graphics.Dispose();
                this._grafx.Dispose();
            }

            this._grafx = grafx;
        }

        /// <summary>
        /// 重写OnPaint
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPaint(PaintEventArgs e)
        {
            try
            {
                this._grafx.Render(e.Graphics);
            }
            catch (Exception ex)
            {
                Loger.Error(ex);
            }
        }

        /// <summary>
        /// 重写OnPaintBackground
        /// </summary>
        /// <param name="pevent"></param>
        protected override void OnPaintBackground(PaintEventArgs pevent)
        {
            //配合构造函数中this.DoubleBuffered = true;解决闪屏问题
            return;
        }




        /// <summary>
        /// 波形分隔线绘制画笔
        /// </summary>
        private Brush _fill = new SolidBrush(Color.Red);
        /// <summary>
        /// 获取或设置分隔线绘制画笔
        /// </summary>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public Brush Fill
        {
            get { return this._fill; }
            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException(nameof(value));
                }

                this._fill.Dispose();
                this._fill = value;
            }
        }

        private Size _ellipseSize = new Size(20, 20);

        public void Clear()
        {
            //var grafx = this._grafx;
            //if (grafx == null)
            //{
            //    return;
            //}

            ////绘制
            //Graphics graphics = grafx.Graphics;
            //graphics.Clear(Color.Red);
            var region = new Region(this.ClientRectangle);
            //region.Exclude(this.ClientRectangle);
            region.MakeEmpty();
            this.Region = region;
        }

        private void Draw_bk()
        {
            var grafx = this._grafx;
            if (grafx == null)
            {
                return;
            }

            try
            {
                //全部绘制
                Graphics graphics = grafx.Graphics;

                //清空所有已绘制的图形
                graphics.Clear(this.BackColor);
                //graphics.Clear(Color.Transparent);

                Brush fill = this._fill;
                Size ellipseSize = this._ellipseSize;

                //200-200
                graphics.FillEllipse(fill, 50, 50, ellipseSize.Width, ellipseSize.Height);

                graphics.FillEllipse(fill, 100, 100, ellipseSize.Width, ellipseSize.Height);

                graphics.FillEllipse(fill, 150, 150, ellipseSize.Width, ellipseSize.Height);

                Region region3 = new Region(new Rectangle(80, 80, 50, 50));
                graphics.ExcludeClip(region3);

                //刷新控件
                this.Refresh();
            }
            catch (Exception ex)
            {
                Loger.Error(ex);
            }
        }

        private int x = 0;
        private int y = 0;
        private const int _offset = 50;
        private const int _step = 10;

        private void Draw()
        {
            var grafx = this._grafx;
            if (grafx == null)
            {
                return;
            }

            try
            {
                //绘制
                Graphics graphics = grafx.Graphics;
                //graphics.Clear(Color.Red);

                LinearGradientBrush linGrBrush = new LinearGradientBrush(
   new Point(0, 10),
   new Point(200, 10),
   Color.FromArgb(255, 255, 0, 0),   // Opaque red
   Color.FromArgb(255, 0, 0, 255));  // Opaque blue



                var reg = new Rectangle(0, 0, this.ClientRectangle.Width - 50, ClientRectangle.Height - 50);
                graphics.FillRectangle(linGrBrush, reg);

                linGrBrush.Dispose();

                this.Region = this.GetRegion();

            }
            catch (Exception ex)
            {
                Loger.Error(ex);
            }
        }


        private Region GetRegion()
        {
            if (x > _offset)
            {
                x = 0;
                y = 0;
            }

            Size ellipseSize = this._ellipseSize;
            System.Drawing.Drawing2D.GraphicsPath graphicsPath = new System.Drawing.Drawing2D.GraphicsPath();
            graphicsPath.AddEllipse(new Rectangle(x + 50, y + 50, ellipseSize.Width, ellipseSize.Height));
            graphicsPath.AddEllipse(new Rectangle(x + 100, y + 100, ellipseSize.Width, ellipseSize.Height));
            graphicsPath.AddEllipse(new Rectangle(x + 150, y + 150, ellipseSize.Width, ellipseSize.Height));

            x += _step;
            y += _step;

            var region = new System.Drawing.Region(graphicsPath);
            //region.Exclude(new System.Drawing.Rectangle(20, 20, 40, 40));
            return region;
        }


        private void Draw_1218_simpole()
        {
            var grafx = this._grafx;
            if (grafx == null)
            {
                return;
            }

            try
            {
                //全部绘制
                Graphics graphics = grafx.Graphics;

                //System.Drawing.Drawing2D.GraphicsPath graphicsPath = new System.Drawing.Drawing2D.GraphicsPath();
                //System.Drawing.Rectangle newRectangle = this.ClientRectangle;
                //graphics.DrawEllipse(System.Drawing.Pens.Black, newRectangle);
                //newRectangle.Inflate(1, 1);
                //graphicsPath.AddEllipse(newRectangle);

                var region = new System.Drawing.Region(new Rectangle(0, 0, 200, 200));
                region.Exclude(new System.Drawing.Rectangle(20, 20, 40, 40));
                this.Region = region;
            }
            catch (Exception ex)
            {
                Loger.Error(ex);
            }
        }

        private void Draw_1218946()
        {
            var grafx = this._grafx;
            if (grafx == null)
            {
                return;
            }

            try
            {
                //全部绘制
                Graphics graphics = grafx.Graphics;

                System.Drawing.Drawing2D.GraphicsPath graphicsPath = new System.Drawing.Drawing2D.GraphicsPath();

                // Set a new rectangle to the same size as the button's 
                // ClientRectangle property.
                System.Drawing.Rectangle newRectangle = this.ClientRectangle;

                // Decrease the size of the rectangle.
                //newRectangle.Inflate(-10, -10);

                // Draw the button's border.
                graphics.DrawEllipse(System.Drawing.Pens.Black, newRectangle);

                // Increase the size of the rectangle to include the border.
                newRectangle.Inflate(1, 1);

                // Create a circle within the new rectangle.
                graphicsPath.AddEllipse(newRectangle);

                // Set the button's Region property to the newly created 
                // circle region.
                var region = new System.Drawing.Region(graphicsPath);
                region.Exclude(new System.Drawing.Rectangle(20, 20, 40, 40));
                this.Region = region;
            }
            catch (Exception ex)
            {
                Loger.Error(ex);
            }
        }


        private void Draw22()
        {
            var grafx = this._grafx;
            if (grafx == null)
            {
                return;
            }

            try
            {
                //全部绘制
                Graphics graphics = grafx.Graphics;

                Point[] polyPoints = {
                    new Point(10, 10),
                    new Point(150, 10),
                    new Point(100, 75),
                    new Point(100, 150)};
                GraphicsPath path = new GraphicsPath();
                path.AddPolygon(polyPoints);

                // Construct a region based on the path.
                Region region = new Region(path);

                // Draw the outline of the region.
                Pen pen = Pens.Black;
                graphics.DrawPath(pen, path);

                // Set the clipping region of the Graphics object.
                graphics.SetClip(region, CombineMode.Replace);

                // Draw some clipped strings.
                FontFamily fontFamily = new FontFamily("Arial");
                Font font = new Font(
                   fontFamily,
                   36, FontStyle.Bold,
                   GraphicsUnit.Pixel);
                SolidBrush solidBrush = new SolidBrush(Color.FromArgb(255, 255, 0, 0));

                graphics.DrawString(
                   "A Clipping Region",
                   font, solidBrush,
                   new PointF(15, 25));

                graphics.DrawString(
                   "A Clipping Region",
                   font,
                   solidBrush,
                   new PointF(15, 68));



                //Region region1 = new Region(new Rectangle(10, 10, 100, 100));
                //region1.MakeEmpty();
                //graphics.ExcludeClip(region1);
                //graphics.FillRectangle(Brushes.Transparent, this.ClientRectangle);
            }
            catch (Exception ex)
            {
                Loger.Error(ex);
            }
        }

        private void DemonstrateRegionData2(PaintEventArgs e)
        {

            //Create a simple region.
            Region region1 = new Region(new Rectangle(10, 10, 100, 100));

            // Extract the region data.
            System.Drawing.Drawing2D.RegionData region1Data = region1.GetRegionData();
            byte[] data1;
            data1 = region1Data.Data;

            // Create a second region.
            Region region2 = new Region();

            // Get the region data for the second region.
            System.Drawing.Drawing2D.RegionData region2Data = region2.GetRegionData();

            // Set the Data property for the second region to the Data from the first region.
            region2Data.Data = data1;

            // Construct a third region using the modified RegionData of the second region.
            Region region3 = new Region(region2Data);

            // Dispose of the first and second regions.
            region1.Dispose();
            region2.Dispose();

            // Call ExcludeClip passing in the third region.
            e.Graphics.ExcludeClip(region3);

            // Fill in the client rectangle.
            e.Graphics.FillRectangle(Brushes.Red, this.ClientRectangle);

            region3.Dispose();

        }





        /// <summary>
        /// 重写Dispose
        /// </summary>
        /// <param name="disposing"></param>
        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);

            this._timer.Dispose();
            if (this._grafx != null)
            {
                this._grafx.Dispose();
                this._grafx = null;
            }

            this.PrimitiveDisposable(this._fill);
            //this.PrimitiveDisposable(this._seleactionGlobalViewAreaBrush);
        }

        private void PrimitiveDisposable(IDisposable disposable)
        {
            if (disposable != null)
            {
                disposable.Dispose();
            }
        }


    }
}
